/** for Random */
import java.util.Random;

/** for JOptionPane */
import javax.swing.JOptionPane;

/**
 * To manage events
 * @author CodeTraders
 * @version 1.0 11/17/12
 */
public class Event {
	/**to get current planet**/
	private final Planet currentPlanet;
	
	/**to get current ship**/
	private final Ship currentShip;
	
	/**to get player**/
	private final Player player;
	
	/**to get main panel**/
	private SpaceTraderMainGUI mainPanel;
	
	/** for num **/
	private int num = 0;
	
	/** for double num2 **/
	private double num2 = 0;
	
	/** for ZERO **/
	private static final int ZERO = 0;
	
	/** for ONE **/
	private static final int ONE = 1;
	
	/** for TWO **/
	private static final int TWO = 2;
	
	/** for THREE **/
	private static final int THREE = 3;
	
	/** for FOUR **/
	private static final int FOUR = 4;
	
	/** for FIVE **/
	private static final int FIVE = 5;

	/** for SIX **/
	private static final int SIX = 6;
	
	/** for SEVEN **/
	private static final int SEVEN = 7;
	
	/** for PAL **/
	private static final int PAL = 8;
	
	/** for NINE **/
	private static final int NINE = 9;
	
	/** for TEN **/
	private static final int TEN = 10;
	
	/** for ELEVEN **/
	private static final int ELEVEN = 11;
	
	/** for TWELVE **/
	private static final int TWELVE = 12;
	
	/** for THIRTEEN **/
	private static final int THIRTEEN = 13;
	
	/** for FOURTEEN **/
	private static final int FOURTEEN = 14;
	
	/** for FIFTEEN **/
	private static final int FIFTEEN = 15;
	
	/** for SIXTEEN **/
	private static final int SIXTEEN = 16;
	
	/** for SEVENTEEN **/
	private static final int SEVENTEEN = 17;
	
	/** for EIGHTTEEN **/
	private static final int EIGHTTEEN = 18;
	
	/** for NINETEEN **/
	private static final int NINETEEN = 19;
	
	/** for TWENTY **/
	private static final int TWENTY = 20;
	
	/** for TWENTYONE **/
	private static final int TWENTYONE = 21;
	
	/** for TWENTYTWO **/
	private static final int TWENTYTWO = 22;
	
	/** for TWENTYTHREE **/
	private static final int TWENTYTHREE = 23;
	
	/** for TWENTYFOUR **/
	private static final int TWENTYFOUR = 24;
	
	/** for TWENTYFIVE **/
	private static final int TWENTYFIVE = 25;
	
	/** for TWENTYSIX **/
	private static final int TWENTYSIX = 26;

	/** for TWENTYSEVEN **/
	private static final int TWENTYSEVEN = 27;
	
	/** for TWENTYEIGHT **/
	private static final int TWENTYEIGHT = 28;
	
	/** for TWENTYNINE **/
	private static final int TWENTYNINE = 29;
	
	/** for THIRTY **/
	private static final int THIRTY = 30;
	
	/** for THIRTYONE **/
	private static final int THIRTYONE = 31;
	
	/** for THIRTYTWO **/
	private static final int THIRTYTWO = 32;
	
	/** for THIRTYTHREE **/
	private static final int THIRTYTHREE = 33;
	
	/** for THIRTYFOUR **/
	private static final int THIRTYFOUR = 34;
	
	/** for SEVENTY **/
	private static final int SEVENTY = 70;
	
	/** for EIGHTY **/
	private static final int EIGHTY = 80;
	
	/** for HUNDRED **/
	private static final int HUNDRED = 100;
	
	/** for HUNDREDTHIRTY **/
	private static final int HUNDREDTHIRTY = 130;
	
	/** for HUNDREDSIXTY **/
	private static final int HUNDREDSIXTY = 160;

	/** for TWOHUNDREDFIFTY **/
	private static final int TWOHUNDREDFIFTY = 250;
	
	/** for FIVEHUNDRED **/
	private static final int FIVEHUNDRED = 500;
	
	/** for HREETHOUSANDS **/
	private static final int THREETHOUSANDS = 3000;
	
	/** for FIVETHOUSANDS **/
	private static final int FIVETHOUSANDS = 5000;
	
	/** for JACKPOTMONEY **/
	private static final int JACKPOTMONEY = 50000;
	
	/** for 0.33 **/
	private static final float POINTTHIRTYTHREE = 0.33f;
	
	/** for 0.95 **/
	private static final float POINTNINETYFIVE = 0.95f;

	/**
	 * constructor for the event
	 */
	public Event() {
		final Ship ship = (Ship) Singleton.INSTANCE.get("ship");
		final Player player = (Player) Singleton.INSTANCE.get("player");
		this.currentPlanet = ship.getCurrentPlanet();
		this.currentShip = ship;
		this.player = player;
	}
	
	/**
	 * to create Event
	 */
	public void createEvent() {
		final Random rand = new Random();
		num = ((Integer) Singleton.INSTANCE.get("difficulty") + 1) * TEN;
		if (player.getPoint() % num == 0) {
			return;
		}
		final int ran = rand.nextInt(TWENTY);
		if (ran == 0) {
			meetPirate();
			return;
		} else if(ran == 1) {
			meetPolice();
			return;
		}
		
		/* jackpot mode
		 * add 500000 money, max fuel, and max life
		 */
		if (rand.nextInt(FIVEHUNDRED) == TWOHUNDREDFIFTY) {
			currentShip.addMoney(JACKPOTMONEY);
			currentShip.setFuel(currentShip.getShipType().getMaxFuel());
			currentShip.setLife(currentShip.getShipType().getHullStrength());
			JOptionPane.showMessageDialog(null, "You won a jackpot!!!");
			mainPanel.updateBottomPanel();
			return;
		}
		
		final String msg = createRandomEventMsg_0(getRandomCase());
		
		if (msg != null) {
			JOptionPane.showMessageDialog(null, msg);
		}
		mainPanel.updateBottomPanel();
		mainPanel.update();
	}
	
	/**
	 * get RandomCase
	 * @return proper number
	 */
	private int getRandomCase() {
		final Random rand = new Random();
		switch ((Integer) Singleton.INSTANCE.get("difficulty")) {
		// always triggers a good event (Beginner)
		case 0:
			return rand.nextInt(FOURTEEN) + FIVE;
		// only triggers a good event (Easy)
		case 1:
			return rand.nextInt(NINETEEN);
		// triggers both good and bad events (Normal)
		case TWO:
			return rand.nextInt(THIRTYFOUR);
		// only triggers a bad event (Hard)
		case THREE:
			return rand.nextInt(TWENTY) + NINETEEN;
		// always triggers a bad event (Impossible)
		case FOUR:
			return rand.nextInt(FIFTEEN) + NINETEEN;
		default:
			return 0;
		}
	}
	
	/**
	 * for random event 
	 * @param n
	 * @return proper message
	 */
	private String createRandomEventMsg_0(int n) {
		switch (n) {
		case 0:
			return "Nothing Happened";
		case FIVE:
			num2 = currentShip.getFuel();
			num2 += (num2 / TWO);
			currentShip.setFuel(num >
			currentShip.getShipType().getMaxFuel() ?
					currentShip.getShipType().getMaxFuel() : num2);
			return "Got Fuel 50%";
		case SIX:
			num2 = currentShip.getFuel();
			num2 += (num2 / THREE);
			currentShip.setFuel(num > currentShip.getShipType().getMaxFuel()
					? currentShip.getShipType().getMaxFuel() : num2);
			return "Got Fuel 30%";
		case SEVEN:
			num2 = currentShip.getShipType().getMaxFuel();
			currentShip.setFuel(num2);
			return "Got Full 100%";
		case PAL:
			num = currentShip.getMoney() + FIVETHOUSANDS;
			currentShip.setMoney(num);
			return "Got Money $5000";
		case NINE:
			num = currentShip.getMoney() + THREETHOUSANDS;
			currentShip.setMoney(num);
			return "Got Money $3000";
		default:
			return createRandomEventMsg_1(n);
		}
	}
	
	/**
	 * for random event 
	 * @param n
	 * @return proper message
	 */
	private String createRandomEventMsg_1(int n) {
		switch (n) {
		case TEN:
			if(currentShip.isCargoSpaceAvailable(1)) {
				currentShip.addGoods(Goods.WATER, 1);
			}
			return "Got 1 WATER";
		case ELEVEN:
			if(currentShip.isCargoSpaceAvailable(1)) {
				currentShip.addGoods(Goods.ROBOTS, 1);
			}
			return "Got 1 ROBOTS";
		case TWELVE:
			if(currentShip.isCargoSpaceAvailable(1)) {
				currentShip.addGoods(Goods.ORE, 1);
			}
			return "Got 1 ORE";
		case THIRTEEN:
			if(currentShip.isCargoSpaceAvailable(1)) {
				currentShip.addGoods(Goods.NARCOTICS, 1);
			}
			return "Got 1 NARCOTICS";
		default:
			return createRandomEventMsg_2(n);
		}
	}
	
	/**
	 * for random event 
	 * @param n
	 * @return proper message
	 */
	private String createRandomEventMsg_2(int n) {
		switch (n) {
		case FOURTEEN:
			if(currentShip.isCargoSpaceAvailable(1)) {
				currentShip.addGoods(Goods.MEDICINE, 1);
			}
			return "Got 1 MEDICINE";
		case FIFTEEN:
			if(currentShip.isCargoSpaceAvailable(1)) {
				currentShip.addGoods(Goods.GAMES, 1);
			}
			return "Got 1 GAMES";
		case SIXTEEN:
			if(currentShip.isCargoSpaceAvailable(1)) {
				currentShip.addGoods(Goods.FURS, 1);
			}
			return "Got 1 FURS";
		case SEVENTEEN:
			if(currentShip.isCargoSpaceAvailable(1)) {
				currentShip.addGoods(Goods.FOOD, 1);
			}
			return "Got 1 FOOD";
		case TWENTYFOUR:
			num2 = currentShip.getLife() / TWO;
			currentShip.setLife(num2);
			return "An asteroid has hit the ship (Ship is 50% Broken)";
		default:
			return createRandomEventMsg_3(n);
		}
	}
	
	/**
	 * for random event 
	 * @param n
	 * @return proper message
	 */
	private String createRandomEventMsg_3(int n) {
		double num2;
		switch (n) {
		case EIGHTTEEN:
			if(currentShip.isCargoSpaceAvailable(1)) {
				currentShip.addGoods(Goods.FIREARMS, 1);
			}
			return "Got 1 FIREARMS";
		case NINETEEN:
			// fuel should be double because double is more accurate than integer
			num2 = currentShip.getFuel() / TWO;
			currentShip.setFuel(num2);
			return "Lost Fuel 50%";
		case TWENTY:
			num2 = currentShip.getFuel() / THREE;
			currentShip.setFuel(num2);
			return "Lost Fuel 30%";
		case TWENTYONE:
			// fuel should be double because double is more accurate than integer
			num = currentShip.getMoney() / TWO;
			// money should be integer
			currentShip.setMoney(num);
			return "Lost Money 50%";
		case TWENTYTWO: 
			// fuel should be double because double is more accurate than integer
			num = Math.round(currentShip.getMoney() * POINTTHIRTYTHREE);
			// money should be integer
			currentShip.setMoney(num);
			return "Lost Money 30%";
		case TWENTYTHREE:
			meetPirate();
			return null;
		case TWENTYFIVE:
			if(currentShip.getGoods()[Goods.WATER.ordinal()] >= 1) {
				currentShip.removeGoods(Goods.WATER, 1);
			}
			return "LOST 1 WATER";
		default:
			return createRandomEventMsg_4(n);
		}
	}
	
	/**
	 * for random event 
	 * @param n
	 * @return proper message
	 */
	private String createRandomEventMsg_4(int n) {
		switch (n) {
		case TWENTYSIX:
			if(currentShip.getGoods()[Goods.ROBOTS.ordinal()] >= 1) {
				currentShip.removeGoods(Goods.ROBOTS, 1);
			}
			return "LOST 1 ROBOTS";
		case TWENTYSEVEN:
			if(currentShip.getGoods()[Goods.ORE.ordinal()] >= 1) {
				currentShip.removeGoods(Goods.ORE, 1);
			}
			return "LOST 1 ORE";
		case TWENTYEIGHT:
			if(currentShip.getGoods()[Goods.NARCOTICS.ordinal()] >= 1) {
				currentShip.removeGoods(Goods.NARCOTICS, 1);
			}
			return "LOST 1 NARCOTICS";
		case TWENTYNINE:
			if(currentShip.getGoods()[Goods.MEDICINE.ordinal()] >= 1) {
				currentShip.removeGoods(Goods.MEDICINE, 1);
			}
			return "LOST 1 MEDICINE";
		default:
			return createRandomEventMsg_5(n);
		}
	}
	
	/**
	 * for random event 
	 * @param n
	 * @return proper message
	 */
	private String createRandomEventMsg_5(int n) {
		switch (n) {
		case THIRTY:
			if(currentShip.getGoods()[Goods.GAMES.ordinal()] >= 1) {
				currentShip.removeGoods(Goods.GAMES, 1);
			}
			return "LOST 1 GAMES";
		case THIRTYONE:
			if(currentShip.getGoods()[Goods.FURS.ordinal()] >= 1) {
				currentShip.removeGoods(Goods.FURS, 1);
			}
			return "LOST 1 FURS";
		case THIRTYTWO:
			if(currentShip.getGoods()[Goods.FOOD.ordinal()] >= 1) {
				currentShip.removeGoods(Goods.FOOD, 1);
			}
			return "LOST 1 FOOD";
		case THIRTYTHREE:
			if(currentShip.getGoods()[Goods.FIREARMS.ordinal()] >= 1) {
				currentShip.removeGoods(Goods.FIREARMS, 1);
			}
			return "LOST 1 FIREARMS";
		default:
			return "Nothing Happened";
		}
	}
	
	/**
	 * for police and pirate's health according to the difficulty
	 * @return health
	 */
	public double pirate_health() {
		double health = 0;
		switch ((int) Singleton.INSTANCE.get("difficulty")) {
		// always triggers a good event (Beginner)
		case ZERO:
			health = SEVENTY;
			break;
			// only triggers a good event (Easy)
		case ONE:
			health = EIGHTY;
			break;
			// triggers both good and bad events (Normal)
		case TWO:
			health = HUNDRED;
			break;
			// only triggers a bad event (Hard)
		case THREE:
			health = HUNDREDTHIRTY;
			break;
			// always triggers a bad event (Impossible)
		case FOUR:
			health = HUNDREDSIXTY;
			break;
		default:
			break;
		}
		return health;
	}
	
	/**
	 * for pirate and police damage according to the difficulty
	 * @return damage
	 */
	public double pirate_power() {
		double power = 0;
		switch ((int) Singleton.INSTANCE.get("difficulty")) {
		// always triggers a good event (Beginner)
		case ZERO:
			power = TEN;
			break;
			// only triggers a good event (Easy)
		case ONE:
			power = FIFTEEN;
			break;
			// triggers both good and bad events (Normal)
		case TWO:
			power = TWENTY;
			break;
			// only triggers a bad event (Hard)
		case THREE:
			power = TWENTYFIVE;
			break;
			// always triggers a bad event (Impossible)
		case FOUR:
			power = THIRTY;
			break;
		default:
			break;
		}
		return power;
	}
	
	/**
	 * when user meet the pirate
	 */
	public void meetPirate() {
		num = -1;
		if (currentShip.hasGadget(Gadget.CLOAK)) {
			num = JOptionPane.showOptionDialog(null,
					"You met a pirate!\nDo you want to fight or hide?", "Pirate",
					JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE,
					null, new String[]{"Hide", "Fight"}, "default");
		}
		if (num == 0) {
			return;
		}
		final double player_power = player.b_Power() + currentShip.getDamage();
		double pirate_life = pirate_health();
		final double pirate_power = pirate_power();
		String msg = null;
		for (int i = 0; i < TWO; i++) {
			currentShip.calcAttack(pirate_power);
			if (currentShip.getLife() <= 0) {
				msg = "You have been defeated by the pirate!!";
				break;
			}
			pirate_life -= player_power;
			if (pirate_life <= 0) {
				msg = "You have defeated the pirate!!," +
						"  Current Life: " + currentShip.getLife();
				break;
			}
		}
		if (msg == null) msg = "You got some damages from a pirate!!," +
				"  Current Life: " + currentShip.getLife();
		JOptionPane.showMessageDialog(null, msg);
		mainPanel.updateBottomPanel();
		mainPanel.update();
	}
	
	/**
	 * when user meet the police
	 */
	public void meetPolice() {
		final Random rand = new Random();
		num = -1;
		while (num == -1) {
			num = JOptionPane.showOptionDialog(null,
			"You met a police!\n Do you want to respond, fight, or run?", "Police",
			JOptionPane.YES_NO_CANCEL_OPTION,
			JOptionPane.INFORMATION_MESSAGE,
			null, new String[]{"Run", "Fight", "Respond"}, "default");
		}
		if (num == TWO) {
			String msg;
			if (currentShip.getMoney() == 0) {
				final Item item = currentShip.getRandomItem();
				if (item != null) {
					currentShip.removeItem(item);
					msg = "You gave " + item;
				} else {
					currentShip.setLife(currentShip.getLife() * POINTNINETYFIVE);
					msg = "Your life was lost by 5% because you didn't " +
							"have any money or item to pay the police";
				}
			} else {
				currentShip.setMoney(
						Math.round(currentShip.getMoney() * POINTNINETYFIVE));
				msg = "You paid 5% tax";
			}
			JOptionPane.showMessageDialog(null, msg);
			mainPanel.updateBottomPanel();
			mainPanel.update();
		} else if (num == 1) {
			fightWithPolice();
		} else if (num == 0) {
			String msg;
			if (currentShip.hasGadget(Gadget.CLOAK)) {
				return;
			} else if (rand.nextInt(FOUR) == ONE) {
				msg = "You successfully ran away!!";
				JOptionPane.showMessageDialog(null, msg);
				mainPanel.updateBottomPanel();
				mainPanel.update();
			} else {
				currentShip.calcAttack
				(currentShip.getShipType().getHullStrength() / TWO);
				msg = "You failed to run away!!";
				JOptionPane.showMessageDialog(null, msg);
				mainPanel.updateBottomPanel();
				mainPanel.update();
			}
		}
	}
	
	/**
	 * when user fights with Police 
	 */
	private void fightWithPolice() {
		final Random rand = new Random();
		final double player_power = player.b_Power() + currentShip.getDamage();
		double pirate_life = pirate_health() + TWENTYFIVE;
		final double pirate_power = pirate_power() + TEN;
		String msg;
		for (int i = 0; i < TWO; i++) {
			currentShip.calcAttack(pirate_power);
			if (currentShip.getLife() <= 0) {
				if (currentShip.getMoney() == 0) {
					Item item = currentShip.getRandomItem();
					if (item != null) {
						currentShip.removeItem(item);
					} else {
						currentShip.setLife(currentShip.getLife() * POINTNINETYFIVE);
					}
				} else {
					//money should be integer value
					currentShip.setMoney(
							Math.round(currentShip.getMoney() * POINTNINETYFIVE));
				}
				msg = "You were defeated by the police and paid tax!!";
				JOptionPane.showMessageDialog(null, msg);
				mainPanel.updateBottomPanel();
				mainPanel.update();
				break;
			}
			pirate_life -= player_power;
			if (pirate_life <= 0) {
				num = rand.nextInt(FIVEHUNDRED) + FIVEHUNDRED;
				currentShip.addMoney(num);
				msg = "You have defeated the police!!\n" +
				"You have successfully robbed " + num + 
				" from the police!, " + "CurrentLife: " +
				currentShip.getLife();
				JOptionPane.showMessageDialog(null, msg);
				mainPanel.updateBottomPanel();
				mainPanel.update();
				break;
			}
		}
	}
	
	/**
	 * to get the current ship
	 * @return currentShip
	 */
	public Ship getShip() {
		return this.currentShip;
	}
	
	/**
	 * to get the currentPlanet
	 * @return currentPlaent
	 */
	public Planet getPlanet() {
		return this.currentPlanet;
	}
	
	/**
	 * to get Goods
	 * @return currentPlanet.getGoods
	 */
	public Goods[] getGoods() {
		return currentPlanet.getGoods();
	}
	
	/**
	 * to set mainPanel
	 * @param m
	 */
	public void setMainPanel(SpaceTraderMainGUI m) {
		this.mainPanel = m;
	}
	
	/**
	 * toString
	 * @return super.toString();
	 */
	public String toString() {
		return super.toString();
	}
}
